home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: delta / whiteline CD Series - delta.iso / tools / anwender / astrolog / sources / io.c < prev    next >
C/C++ Source or Header  |  1995-11-25  |  24KB  |  725 lines

  1. /*
  2. ** Astrolog (Version 4.40) File: io.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1995 by Walter D. Pullen
  6. ** (astara@u.washington.edu). Permission is granted to freely use and
  7. ** distribute these routines provided one doesn't sell, restrict, or
  8. ** profit from them in any way. Modification is allowed provided these
  9. ** notices remain with any altered or edited versions of the program.
  10. **
  11. ** The main planetary calculation routines used in this program have
  12. ** been Copyrighted and the core of this program is basically a
  13. ** conversion to C of the routines created by James Neely as listed in
  14. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  15. ** available from Matrix Software. The copyright gives us permission to
  16. ** use the routines for personal use but not to sell them or profit from
  17. ** them in any way.
  18. **
  19. ** The PostScript code within the core graphics routines are programmed
  20. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  21. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  22. **
  23. ** The extended accurate ephemeris databases and formulas are from the
  24. ** calculation routines in the program "Placalc" and are programmed and
  25. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  26. ** (alois@azur.ch). The use of that source code is subject to
  27. ** regulations made by Astrodienst Zurich, and the code is not in the
  28. ** public domain. This copyright notice must not be changed or removed
  29. ** by any user of this program.
  30. **
  31. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  32. ** X Window graphics initially programmed 10/23-29/1991.
  33. ** PostScript graphics initially programmed 11/29-30/1992.
  34. ** Last code change made 1/29/1995.
  35. */
  36.  
  37. #include "astrolog.h"
  38.  
  39.  
  40. /*
  41. ******************************************************************************
  42. ** File IO Routines.
  43. ******************************************************************************
  44. */
  45.  
  46. /* Open the file indicated by the given string and return the file's stream */
  47. /* pointer, or NULL if the file couldn't be found or opened. All parts of   */
  48. /* the program which open files to read call this routine. We look in       */
  49. /* several various locations and directories for the file before giving up. */
  50.  
  51. FILE *FileOpen(szFile, nFileMode)
  52. char *szFile;
  53. int nFileMode;
  54. {
  55.   FILE *file;
  56.   char name[cchSzDef], mode[3];
  57. #ifdef ENVIRON
  58.   char *env;
  59. #endif
  60.  
  61.   /* Some file types we want to open as binary instead of Ascii. */
  62.   sprintf(mode, "r%s", nFileMode == 2 ? "b" : "");
  63.  
  64.   /* First look for the file in the current directory. */
  65.   file = fopen(szFile, mode);
  66.   if (file != NULL)
  67.     return file;
  68.  
  69. #ifdef ENVIRON
  70.   /* Next look for the file in the directory indicated by the version */
  71.   /* specific system environment variable.                            */
  72.   sprintf(name, "%s%s", ENVIRONVER, szVersionCore);
  73.   env = getenv(name);
  74.   if (env && *env) {
  75.     sprintf(name, "%s%c%s", env, chDirSep, szFile);
  76.     file = fopen(name, mode);
  77.     if (file != NULL)
  78.       return file;
  79.   }
  80.  
  81.   /* Next look in the directory in the general environment variable. */
  82.   env = getenv(ENVIRONALL);
  83.   if (env && *env) {
  84.     sprintf(name, "%s%c%s", env, chDirSep, szFile);
  85.     file = fopen(name, mode);
  86.     if (file != NULL)
  87.       return file;
  88.   }
  89.  
  90.   /* Next look in the directory in the version prefix environment variable. */
  91.   env = getenv(ENVIRONVER);
  92.   if (env && *env) {
  93.     sprintf(name, "%s%c%s", env, chDirSep, szFile);
  94.     file = fopen(name, mode);
  95.     if (file != NULL)
  96.       return file;
  97.   }
  98. #endif
  99.  
  100.   /* Finally look in one of several directories specified at compile time. */
  101.   sprintf(name, "%s%c%s", nFileMode == 0 ? DEFAULT_DIR :
  102.     (nFileMode == 1 ? CHART_DIR : EPHE_DIR), chDirSep, szFile);
  103.   file = fopen(name, mode);
  104.   if (file == NULL && nFileMode == 1) {
  105.     /* If the file was never found, print an error (unless we were looking */
  106.     /* for a certain file type, e.g. the optional astrolog.dat file).      */
  107.     sprintf(name, "File '%s' not found.", szFile);
  108.     PrintError(name);
  109.   }
  110.   return file;
  111. }
  112.  
  113. /*
  114. #####################################################################
  115. Ajout personnel Abel Philipe 26/7/95
  116. La fonction feof semble buguée. Je la remplace par celle ci-dessous :
  117. #####################################################################
  118. */
  119. #ifdef ATARI
  120. int feof2(FILE *file)
  121. {
  122.     int eof=getc(file);
  123.     if (eof!=EOF)
  124.     {
  125.         ungetc(eof,file);
  126.         return(0);
  127.     }
  128.     else
  129.         return(eof);
  130. }
  131. #endif
  132.  
  133.  
  134. /* This is Astrolog's generic file processing routine, which handles chart */
  135. /* info files, position files, and config files. Given a file name or a    */
  136. /* file handle, run through each line as a series of command switches.     */
  137.  
  138. bool FProcessSwitchFile(szFile, file)
  139. char *szFile;
  140. FILE *file;
  141. {
  142.   char szLine[cchSzMax], *argv[MAXSWITCHES], ch;
  143.   int argc, i;
  144.  
  145.   if (file == NULL)
  146.     file = FileOpen(szFile, 0);
  147.   if (file == NULL)
  148.     return fFalse;
  149.  
  150.   /* All files have to begin with the -@ switch file type identifier. */
  151.   ch = getc(file); ungetc(ch, file);
  152.   if (ch != '@') {
  153.     sprintf(szLine, "The command file '%s' is not in any valid format.",
  154.       szFile);
  155.     PrintWarning(szLine);
  156.     return fFalse;
  157.   }
  158.  
  159. #ifdef ATARI
  160.   while (!feof2(file)) {
  161.     while (!feof2(file) && (ch = getc(file)) < ' ')
  162.       ;
  163.     for (szLine[0] = ch, i = 1; i < cchSzMax && !feof2(file) &&
  164. #else
  165.   while (!feof(file)) {
  166.     while (!feof(file) && (ch = getc(file)) < ' ')
  167.       ;
  168.     for (szLine[0] = ch, i = 1; i < cchSzMax && !feof(file) &&
  169. #endif
  170.       (szLine[i] = getc(file)) >= ' '; i++)
  171.       ;
  172.     szLine[i] = chNull;
  173.     argc = NParseCommandLine(szLine, argv);
  174.     if (!FProcessSwitches(argc, argv))
  175.       return fFalse;
  176.   }
  177.   return fTrue;
  178. }
  179.  
  180.  
  181. /* Take the current chart information, and write it out to the file   */
  182. /* as indicated by the -o switch. This is only executed at the end of */
  183. /* program execution if the -o switch is in effect.                   */
  184.  
  185. bool FOutputData()
  186. {
  187.   char sz[cchSzDef];
  188.   FILE *file;
  189.   int i, j;
  190.   real rT;
  191.  
  192.   file = fopen(is.szFileOut, "w");  /* Create and open the file for output. */
  193.   if (file == NULL) {
  194.     sprintf(sz, "File %s can not be created.", is.szFileOut);
  195.     PrintError(sz);
  196.     return fFalse;
  197.   }
  198.   if (!us.fWritePos) {
  199.  
  200.     /* Write the chart information to the file. */
  201.  
  202.     if (Mon < 1) {
  203.       fclose(file);
  204.       PrintError("Can't output chart with no time/space to file.");
  205.       return fFalse;
  206.     }
  207.     if (us.fWriteOld) {
  208.       fprintf(file, "%d\n%d\n%d\n%.2f\n%.2f\n%.2f\n%.2f\n",
  209.         Mon, Day, Yea, Tim, Zon-Dst, Lon, Lat);
  210.     } else {
  211.       fprintf(file, "@0102  ; %s chart info.\n", szAppName);
  212.       i = us.fAnsi;
  213.       us.fAnsi = fFalse;
  214.       fprintf(file, "%cqb %c%c%c %d %d %s %s %s %s\n", chSwitch, chMon3(Mon),
  215.         Day, Yea, SzTim(Tim), Dst == 0.0 ? "ST" : (Dst == 1.0 ? "DT" :
  216.         SzZone(Dst)), SzZone(-Zon), SzLocation(Lon, Lat));
  217.       fprintf(file, "%czi \"%s\" \"%s\"\n", chSwitch, ciMain.nam, ciMain.loc);
  218.       us.fAnsi = i;
  219.     }
  220.   } else {
  221.  
  222.     /* However, if the -o0 switch is in effect, then write the actual */
  223.     /* positions of the planets and houses to the file instead.       */
  224.  
  225.     if (us.fWriteOld) {
  226.       for (i = 1; i <= oNorm; i++) {
  227.         j = (int)planet[i];
  228.         fprintf(file, "%c%c%c: %2d %2d %10.7f\n", chObj3(i),
  229.           j%30, j/30+1, RFract(planet[i])*60.0);              /* Position */
  230.         rT = planetalt[i];
  231.         fprintf(file, "[%c]: %3d %12.8f\n",                   /* Altitude */
  232.           ret[i] >= 0.0 ? 'D' : chRet, (int)(RSgn(rT)*
  233.           RFloor(RAbs(rT))), (rT-(real)(int)rT)*60.0);     /* Retrograde? */
  234.         if (i == oNod)
  235.           i = oFor-1;
  236.         else if (i == oFor)
  237.           i = oMC -1;
  238.         else if (i == oMC)
  239.           i = oAsc-1;
  240.         else if (i == oAsc)
  241.           i = oVtx-1;
  242.         else if (i == oVtx)    /* Skip minor cusps to write uranians  */
  243.           i = us.fUranian ? uranLo-1 : cObj;
  244.       }
  245.       for (i = 1; i <= cSign/2; i++) {   /* Write first six cusp positions */ 
  246.         j = (int)house[i];
  247.         fprintf(file, "H_%c: %2d %2d %10.7f\n",
  248.           'a'+i-1, j%30, j/30+1, RFract(house[i])*60.0);
  249.       }
  250.  
  251.     } else {
  252.       fprintf(file, "@0203  ; %s chart positions.\n", szAppName);
  253.       for (i = 1; i <= cObj; i++) if (!ignore[i] || FCusp(i)) {
  254.         fprintf(file, "%cYF ", chSwitch);
  255.         if (i <= oNorm)
  256.           fprintf(file, "%c%c%c", chObj3(i));
  257.         else
  258.           fprintf(file, "%3d", i);
  259.         rT = FBetween(i, cuspLo-1+4, cuspLo-1+9) ?
  260.           house[i-(cuspLo-1)] : planet[i];
  261.         j = (int)rT;
  262.         fprintf(file, ":%3d %c%c%c%13.9f,%4d%13.9f,",
  263.           j%30, chSig3(j/30+1), RFract(rT)*60.0,
  264.           (int)planetalt[i], RFract(RAbs(planetalt[i]))*60.0);
  265.         rT = i > oNorm ? 999.0 : (i == oMoo && !us.fPlacalc ? 0.0026 :
  266.           RSqr(spacex[i]*spacex[i]+spacey[i]*spacey[i]+spacez[i]*spacez[i]));
  267.         fprintf(file, "%14.9f%14.9f\n", DFromR(ret[i]), rT);
  268.       }
  269.     }
  270.   }
  271.  
  272.   /* Now write any extra strings that were on the command line after the -o */
  273.   /* specification but before the next switch, to the file as comments.     */
  274.  
  275.   for (i = 1; i < is.cszComment; i++) {
  276.     is.rgszComment++;
  277.     fprintf(file, "%s%s\n", us.fWriteOld ? "" : "; ", is.rgszComment[1]);
  278.   }
  279.   fclose(file);
  280.   return fTrue;
  281. }
  282.  
  283.  
  284. /*
  285. ******************************************************************************
  286. ** User Input Routines.
  287. ******************************************************************************
  288. */
  289.  
  290. /* Given a string, return an index number corresponding to what the string */
  291. /* indicates, based on a given parsing mode. In most cases this is mainly  */
  292. /* looking up a string in the appropriate array and returning the index.   */
  293.  
  294. int NParseSz(szEntry, pm)
  295. char *szEntry;
  296. int pm;
  297. {
  298.   char szLocal[cchSzMax], *sz, ch0, ch1, ch2;
  299.   int cch, n, i;
  300.  
  301.   /* First strip off any leading or trailing spaces. */
  302.   for (cch = 0; szLocal[cch] = szEntry[cch]; cch++)
  303.     ;
  304.   while (cch && szLocal[cch-1] <= ' ')
  305.     szLocal[--cch] = chNull;
  306.   for (sz = szLocal; *sz && *sz <= ' '; sz++, cch--)
  307.     ;
  308.  
  309.   if (cch >= 3) {
  310.     ch0 = ChCap(sz[0]); ch1 = ChUncap(sz[1]); ch2 = ChUncap(sz[2]);
  311.     switch (pm) {
  312.     /* Parse months, e.g. "February" or "Feb" -> 2 for February. */
  313.     case pmMon:
  314.       for (i = 1; i <= cSign; i++) {
  315.         if (ch0 == szMonth[i][0] && ch1 == szMonth[i][1] &&
  316.           ch2 == szMonth[i][2])
  317.           return i;
  318.       }
  319.       break;
  320.     /* Parse planets, e.g. "Jupiter" or "Jup" -> 6 for Jupiter. */
  321.     case pmObject:
  322.       for (i = 1; i <= cObj; i++) {
  323.         if (ch0 == szObjName[i][0] && ch1 == szObjName[i][1] &&
  324.           ch2 == szObjName[i][2])
  325.           return i;
  326.       }
  327.       if (ch0 == 'L' && ch1 == 'i' && ch2 == 'l')
  328.         return oLil;
  329.       if (ch0 == 'S' && ch1 == '.' && ch2 == 'n')
  330.         return oSou;
  331.       break;
  332.     /* Parse aspects, e.g. "Conjunct" or "Con" -> 1 for the Conjunction. */
  333.     case pmAspect:
  334.       for (i = 1; i <= cAspect; i++) {
  335.         if (ch0 == szAspectAbbrev[i][0] &&
  336.           ch1 == ChUncap(szAspectAbbrev[i][1]) &&
  337.           ch2 == szAspectAbbrev[i][2])
  338.           return i;
  339.       }
  340.       break;
  341.     /* Parse house systems, e.g. "Koch" or "Koc" -> 1 for Koch houses. */
  342.     case pmSystem:
  343.       for (i = 1; i <= cSystem; i++) {
  344.         if (ch0 == szSystem[i][0] && ch1 == szSystem[i][1] &&
  345.           ch2 == szSystem[i][2])
  346.           return i;
  347.       }
  348.     /* Parse zodiac signs, e.g. "Scorpio" or "Sco" -> 8 for Scorpio. */
  349.     case pmSign:
  350.       for (i = 1; i <= cSign; i++) {
  351.         if (ch0 == szSignName[i][0] && ch1 == szSignName[i][1] &&
  352.           ch2 == szSignName[i][2])
  353.           return i;
  354.       }
  355.     /* Parse colors, e.g. "White" or "Whi" -> 15 for White. */
  356.     case pmColor:
  357.       for (i = 0; i < 16 ; i++) {
  358.         if (ch0 == szColor[i][0] && ch1 == szColor[i][1] &&
  359.           ch2 == ChUncap(szColor[i][2]))
  360.           return i;
  361.       }
  362.     }
  363.   }
  364.   n = atoi(sz);
  365.  
  366.   if (pm == pmYea) {
  367.     /* For years, process any "BC" (or "B.C.", "b.c", and variations) and   */
  368.     /* convert an example such as "5BC" to -4. For negative years, note the */
  369.     /* difference of one, as 1AD was preceeded by 1BC, with no year zero.   */
  370.     i = Max(cch-1, 0);
  371.     if (i && sz[i] == '.')
  372.       i--;
  373.     if (i && ChCap(sz[i]) == 'C')
  374.       i--;
  375.     if (i && sz[i] == '.')
  376.       i--;
  377.     if (i && ChCap(sz[i]) == 'B')
  378.       n = 1 - n;
  379.   }
  380.   return n;
  381. }
  382.  
  383.  
  384. /* Given a string, return a floating point number corresponding to what the  */
  385. /* string indicates, based on a given parsing mode, like above for integers. */
  386.  
  387. real RParseSz(szEntry, pm)
  388. char *szEntry;
  389. int pm;
  390. {
  391.   char szLocal[cchSzMax], *sz, *pch, ch;
  392.   int cch, i, f = fFalse;
  393.   real r;
  394.  
  395.   /* First strip off any leading or trailing spaces. */
  396.   for (cch = 0; szLocal[cch] = szEntry[cch]; cch++)
  397.     ;
  398.   while (cch && szLocal[cch-1] <= ' ')
  399.     szLocal[--cch] = chNull;
  400.   for (sz = szLocal; *sz && *sz <= ' '; sz++, cch--);
  401.     ;
  402.   /* Capitalize all letters and make colons be periods to be like numbers. */
  403.   for (pch = sz; *pch; pch++) {
  404.     ch = *pch;
  405.     if (ch == ':')
  406.       ch = '.';
  407.     else
  408.       ch = ChCap(ch);
  409.     *pch = ch;
  410.   }
  411.   ch = sz[0];
  412.  
  413.   if (pm == pmTim) {
  414.     /* For times, process "Noon" and "Midnight" (or just "N" and "M"). */
  415.     if (ch == 'N')
  416.       return 12.0;
  417.     else if (ch == 'M')
  418.       return 0.0;
  419.   } else if (pm == pmDst) {
  420.     /* For the Daylight time flag, "Daylight", "Yes", and "True" (or just */
  421.     /* their first characters) are all indications to be ahead one hour.  */
  422.     if (ch == 'D' || ch == 'Y' || ch == 'T')
  423.       return 1.0;
  424.     /* "Standard", "No", and "False" mean the normal zero offset. */
  425.     else if (ch == 'S' || ch == 'N' || ch == 'F')
  426.       return 0.0;
  427.   } else if (pm == pmZon) {
  428.     /* For time zones, see if the abbrev is in a table, e.g. "EST" -> 5. */
  429.     for (i = 0; i < cZone; i++)
  430.       if (NCompareSz(sz, szZon[i]) == 0)
  431.         return rZon[i];
  432.   } else if (pm == pmLon || pm == pmLat) {
  433.     /* For locations, negate the value for an "E" or "S" in the middle    */
  434.     /* somewhere (e.g. "105E30" or "27:40S") for eastern/southern values. */
  435.     for (i = 0; i < cch; i++) {
  436.       ch = sz[i];
  437.       if (FCapCh(ch)) {
  438.         if (ch == 'E' || ch == 'S')
  439.           f = fTrue;
  440.         sz[i] = '.';
  441.         i = cch;
  442.       }
  443.     }
  444.     ch = sz[0];
  445.   }
  446.  
  447.   /* Anything still at this point should be in a numeric format. */
  448.   if (!FNumCh(ch) && ch != '+' && ch != '-' && ch != '.')
  449.     return rLarge;
  450.   r = (f ? -1.0 : 1.0) * atof(sz);
  451.  
  452.   if (pm == pmTim) {
  453.     /* Backtrack over any time suffix, i.e. "AM", "p.m." and variations. */
  454.     i = Max(cch-1, 0);
  455.     if (i && sz[i] == '.')
  456.       i--;
  457.     if (i && sz[i] == 'M')
  458.       i--;
  459.     if (i && sz[i] == '.')
  460.       i--;
  461.     if (i) {
  462.       ch = sz[i];
  463.       if (ch == 'A')                   /* Adjust value appropriately */
  464.         r = r >= 12.0 ? r-12.0 : r;    /* if AM or PM suffix.        */
  465.       else if (ch == 'P')
  466.         r = r >= 12.0 ? r : r+12.0;
  467.     }
  468.   }
  469.   return r;
  470. }
  471.  
  472.  
  473. /* Stop and wait for the user to enter a line of text given a prompt to */
  474. /* display and a string buffer to fill with it.                         */
  475.  
  476. void InputString(szPrompt, sz)
  477. char *szPrompt, *sz;
  478. {
  479.   FILE *file;
  480.  
  481.   file = S; S = stdout;
  482.   PrintSz(szPrompt);
  483.   AnsiColor(kYellow);
  484.   PrintSz(" > ");
  485.   AnsiColor(kDefault);
  486.   if (gets(sz) == NULL)    /* Pressing control-D will terminate the */
  487.     Terminate(tcForce);    /* program (at least on some machines.)  */
  488.   S = file;
  489.   is.cchCol = 0;
  490. }
  491.  
  492.  
  493. /* Prompt the user for a floating point value, parsing as appropriate, and */
  494. /* make sure it conforms to the specified bounds before returning it.      */
  495.  
  496. int NInputRange(szPrompt, low, high, pm)
  497. char *szPrompt;
  498. int low, high;
  499. int pm;
  500. {
  501.   char szLine[cchSzDef];
  502.   int n;
  503.  
  504.   loop {
  505.     InputString(szPrompt, szLine);
  506.     n = NParseSz(szLine, pm);
  507.     if (FBetween(n, low, high))
  508.       return n;
  509.     sprintf(szLine, "Value %d out of range from %d to %d.", n, low, high);
  510.     PrintWarning(szLine);
  511.   }
  512. }
  513.  
  514.  
  515. /* This is identical to above except it takes/returns floating point values. */
  516.  
  517. real RInputRange(szPrompt, low, high, pm)
  518. char *szPrompt;
  519. real low, high;
  520. int pm;
  521. {
  522.   char szLine[cchSzDef];
  523.   real r;
  524.  
  525.   loop {
  526.     InputString(szPrompt, szLine);
  527.     r = RParseSz(szLine, pm);
  528.     if (FBetween(r, low, high))
  529.       return r;
  530.     sprintf(szLine, "Value %.0f out of range from %.0f to %.0f.",
  531.       r, low, high);
  532.     PrintWarning(szLine);
  533.   }
  534. }
  535.  
  536.  
  537. /* This important procedure gets all the parameters defining the chart that  */
  538. /* will be worked with later. Given a "filename", it gets from it all the    */
  539. /* pertinent chart information. This is more than just reading from a file - */
  540. /* the procedure also takes care of the cases of prompting the user for the  */
  541. /* information and using the time functions to determine the date now - the  */
  542. /* program considers these cases "virtual" files. Furthermore, when reading  */
  543. /* from a real file, we have to check if it was written in the -o0 format.   */
  544.  
  545. bool FInputData(szFile)
  546. char *szFile;
  547. {
  548.   FILE *file;
  549.   char sz[cchSzDef], ch;
  550.   int i, fT;
  551.   real k, l, m;
  552.  
  553.   /* If we are to read from the virtual file "nul" that means to leave the */
  554.   /* chart information alone with whatever settings it may have already.   */
  555.  
  556.   if (NCompareSz(szFile, szNulCore) == 0) {
  557.     is.fHaveInfo = fTrue;
  558.     return fTrue;
  559.   }
  560.  
  561.   /* If we are to read from the virtual file "set" then that means use a   */
  562.   /* particular set of chart information generated earlier in the program. */
  563.  
  564.   if (NCompareSz(szFile, szSetCore) == 0) {
  565.     is.fHaveInfo = fTrue;
  566.     ciCore = ciSave;
  567.     return fTrue;
  568.   }
  569.  
  570. #ifdef TIME
  571.   /* If we are to read from the file "now" then that means use the time */
  572.   /* functions to calculate the present date and time.                  */
  573.  
  574.   if (NCompareSz(szFile, szNowCore) == 0) {
  575.     is.fHaveInfo = fTrue;
  576.     SS = us.dstDef; ZZ = us.zonDef; OO = us.lonDef; AA = us.latDef;
  577.     GetTimeNow(&MM, &DD, &YY, &TT, ZZ-SS);
  578.     return fTrue;
  579.   }
  580. #endif
  581.  
  582.   /* If we are to read from the file "tty" then that means prompt the user */
  583.   /* for all the chart information.                                        */
  584.  
  585.   if (NCompareSz(szFile, szTtyCore) == 0) {
  586.     file = S; S = stdout;
  587.     if (!us.fNoSwitches) {
  588.       /* Temporarily disable an internal redirection of output to a file  */
  589.       /* because we always want user headers and prompts to be displayed. */
  590.  
  591.       AnsiColor(kWhite);
  592.       sprintf(sz, "** %s version %s ", szAppName, szVersionCore); PrintSz(sz);
  593.       sprintf(sz, "(See '%cHc' switch for copyrights and credits.) **\n",
  594.         chSwitch); PrintSz(sz);
  595.       AnsiColor(kDefault);
  596.       sprintf(sz, "   Invoke as '%s %cH' for list of command line options.\n",
  597.         ProcessProgname(is.szProgName), chSwitch); PrintSz(sz);
  598.     }
  599.  
  600.     MM = NInputRange("Enter month for chart (e.g. '8' 'Aug')",
  601.       1, 12, pmMon);
  602.     DD = NInputRange("Enter day   for chart (e.g. '1' '31') ",
  603.       1, DayInMonth(MM, 0), pmDay);
  604.     YY = NInputRange("Enter year  for chart (e.g. '1995')   ",
  605.       -5000, 5000, pmYea);
  606.     if (FBetween(YY, 0, 99)) {
  607.       sprintf(sz,
  608.         "Assuming first century A.D. is really meant instead of %d.",
  609.         1900 + YY);
  610.       PrintWarning(sz);
  611.     }
  612.     TT = RInputRange("Enter time  for chart (e.g. '18:30' '6:30pm')  ",
  613.       -2.0, 24.0, pmTim);
  614.     SS = us.fWriteOld ? 0.0 :
  615.       RInputRange("Enter if Daylight time in effect (e.g. 'y' '1')",
  616.       -24.0, 24.0, pmDst);
  617.     ZZ = RInputRange("Enter time zone (e.g. '5' 'ET' for Eastern)    ",
  618.       -24.0, 24.0, pmZon);
  619.     if ((int)(RFract(ZZ) * 100.0 + rRound) == 50) {
  620.       PrintWarning(
  621.         "Assuming unusual zone of 50 minutes after the hour instead of 30.");
  622.     }
  623.     OO = RInputRange("Enter Longitude of place (e.g. '122W20')",
  624.       -rDegHalf, rDegHalf, pmLon);
  625.     AA = RInputRange("Enter Latitude  of place (e.g. '47N36') ",
  626.       -rDegQuad, rDegQuad, pmLat);
  627.     if (!us.fWriteOld) {
  628.       InputString("Enter name or title for chart ", sz);
  629.       ciCore.nam = SzPersist(sz);
  630.       InputString("Enter name of city or location", sz);
  631.       ciCore.loc = SzPersist(sz);
  632.     }
  633.     PrintL();
  634.     is.cchRow = 0;
  635.     S = file;
  636.     return fTrue;
  637.   }
  638.  
  639.   /* Now that the special cases are taken care of, we can assume we are */
  640.   /* to read from a real file.                                          */
  641.  
  642.   file = FileOpen(szFile, 1);
  643.   if (file == NULL)
  644.     return fFalse;
  645.   is.fHaveInfo = fTrue;
  646.   ch = getc(file); ungetc(ch, file);
  647.  
  648.   /* Read the chart parameters from a standard command switch file. */
  649.  
  650.   if (ch == '@') {
  651.     fT = is.fSzPersist; is.fSzPersist = fFalse;
  652.     if (!FProcessSwitchFile(szFile, file))
  653.       return fFalse;
  654.     is.fSzPersist = fT;
  655.  
  656.   /* Read the chart info from an older style -o list of seven numbers. */
  657.  
  658.   } else if (FNumCh(ch)) {
  659.     SS = 0.0;
  660.     fscanf(file, "%d%d%d", &MM, &DD, &YY);
  661.     fscanf(file, "%lf%lf%lf%lf", &TT, &ZZ, &OO, &AA);
  662.     if (!FValidMon(MM) || !FValidDay(DD, MM, YY) || !FValidYea(YY) ||
  663.       !FValidTim(TT) || !FValidZon(ZZ) || !FValidLon(OO) || !FValidLat(AA)) {
  664.       PrintWarning("Values in old style chart info file are out of range.");
  665.       return fFalse;
  666.     }
  667.  
  668.   /* Read the actual chart positions from a file produced with the -o0. */
  669.  
  670.   } else if (ch == 'S') {
  671.     MM = -1;
  672.  
  673.     /* Hack: A negative month value means the chart parameters are invalid, */
  674.     /* hence -o0 is in effect and we can assume the chart positions are     */
  675.     /* already in memory so we don't have to calculate them later.          */
  676.  
  677.     for (i = 1; i <= oNorm; i++) {
  678.       fscanf(file, "%s%lf%lf%lf", sz, &k, &l, &m);
  679.       planet[i] = Mod((l-1.0)*30.0+k+m/60.0);
  680.       fscanf(file, "%s%lf%lf", sz, &k, &l);
  681.       if ((m = k+l/60.0) > rDegHalf)
  682.         m = rDegMax - m;
  683.       planetalt[i] = m;
  684.       ret[i] = RFromD(sz[1] == 'D' ? 1.0 : -1.0);
  685.  
  686.       /* -o0 files from versions 3.05 and before don't have the uranians in  */
  687.       /* them. Be prepared to skip over them in old files for compatibility. */
  688.  
  689.       if (i == oVtx) {
  690.         while (getc(file) >= ' ')
  691.           ;
  692.         if ((ch = getc(file)) != 'H')
  693.           i = cuspHi;
  694.         else
  695.           i = cObj;
  696.       }
  697.       if (i == oNod)
  698.         i = oFor-1;
  699.       else if (i == oFor)
  700.         i = oLil-1;
  701.       else if (i == oLil)
  702.         i = oEP -1;
  703.       else if (i == oEP)
  704.         i = oVtx-1;
  705.     }
  706.     for (i = 1; i <= cSign/2; i++) {
  707.       fscanf(file, "%s%lf%lf%lf", sz, &k, &l, &m);
  708.       house[i+6] = Mod((house[i] = Mod((l-1.0)*30.0+k+m/60.0))+rDegHalf);
  709.     }
  710.     for (i = 1; i <= cSign; i++)
  711.       planet[cuspLo-1+i] = house[i];
  712.     planet[oMC] = planet[oLil]; planet[oNad] = Mod(planet[oMC]  + rDegHalf);
  713.     planet[oAsc] = planet[oEP]; planet[oDes] = Mod(planet[oAsc] + rDegHalf);
  714.     planet[oSou] = Mod(planet[oNod] + rDegHalf); ret[oSou] = ret[oNod];
  715.  
  716.   } else {
  717.     PrintWarning("The chart info file is not in any valid format.");
  718.     return fFalse;
  719.   }
  720.   fclose(file);
  721.   return fTrue;
  722. }
  723.  
  724. /* io.c */
  725.